package pkg.genericity.annot;

import java.lang.reflect.Field;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;

import org.hibernate.exception.DataException;

/**
 * 
 * @author Farrukh Shakil
 * Annotation parser
 */
public class Parser {
	
	private static Set<Field> required=null;
	private static Set<Class<?>> parsed=null;
	private static Set<Field> autoIncFields=null;
	static {
		required = new HashSet<Field>();
		parsed = new HashSet<Class<?>>();
		autoIncFields= new HashSet<Field>();
	}
	
	/**
	 * Parses a bean class
	 * @param clazz
	 */
	public void parse(Class<?> clazz)  {
		Field []fields = clazz.getDeclaredFields();
		for (Field field:fields) {
			if (field.isAnnotationPresent(Required.class)) {
				synchronized(this) { required.add(field); }
			}
			if ( field.isAnnotationPresent(AutoIncrement.class) 
					&& (!autoIncFields.contains(field))
					&& field.getType().equals(Integer.class) || field.getType().equals(Double.class) || field.getType().equals(int.class) ) 
			{
				if (!field.getName().toLowerCase().equals("id")) {
					throw new DataException("Invalid autoincrement field. Only field named 'id' is allowed to autoincrement", new SQLException());
				}
				synchronized(this) { autoIncFields.add(field);	}
			}
		}
		synchronized(this) {
			parsed.add(clazz);
		}
	}
	
	/**
	 * Is the given field an autoincrement field
	 * @param field
	 * @return
	 */
	public Boolean isAutoIncrement(Field field)
	{
		if (! parsed.contains(field.getDeclaringClass())) {
			try {
				parse(field.getDeclaringClass());
			} catch (Exception e) {
				e.printStackTrace();
				return false;
			}
		}
		return autoIncFields.contains(field);
		
	}
	
	/**
	 * Is the given field required
	 * @param field
	 * @return
	 */
	public Boolean isRequired(Field field)
	{
		if (! parsed.contains(field.getDeclaringClass())) {
			try {
				parse(field.getDeclaringClass());
			} catch (Exception e) {
				e.printStackTrace();
				return false;
			}
		}
		return required.contains(field);
	}
	
}
